/**
* This file is protected by Copyright.
* Please refer to the COPYRIGHT file distributed with this source distribution.
*
* This file is part of REDHAWK IDE.
*
* All rights reserved. This program and the accompanying materials are made available under
* the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html.
*
*/
package gov.redhawk.ui.editor;
import gov.redhawk.eclipsecorba.library.IdlLibrary;
import gov.redhawk.eclipsecorba.library.util.RefreshIdlLibraryJob;
import gov.redhawk.internal.ui.ScaIdeConstants;
import gov.redhawk.internal.ui.editor.validation.ValidatingEContentAdapter;
import gov.redhawk.ui.RedhawkUiActivator;
import gov.redhawk.ui.util.ViewerUtil;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EventObject;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import mil.jpeojtrs.sca.util.CorbaUtils;
import mil.jpeojtrs.sca.validator.AdvancedEObjectValidator;
import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.observable.IObservable;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExecutableExtension;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.emf.common.command.BasicCommandStack;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.command.CommandStack;
import org.eclipse.emf.common.command.CommandStackListener;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.ui.dialogs.DiagnosticDialog;
import org.eclipse.emf.common.ui.viewer.IViewerProvider;
import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.databinding.EMFDataBindingContext;
import org.eclipse.emf.databinding.edit.EditingDomainEObjectObservableValue;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EValidator;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.domain.IEditingDomainProvider;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.provider.IDisposable;
import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory;
import org.eclipse.emf.edit.ui.dnd.EditingDomainViewerDropAdapter;
import org.eclipse.emf.edit.ui.dnd.LocalTransfer;
import org.eclipse.emf.edit.ui.dnd.ViewerDragAdapter;
import org.eclipse.emf.edit.ui.provider.UnwrappingSelectionProvider;
import org.eclipse.emf.edit.ui.util.EditUIUtil;
import org.eclipse.emf.transaction.NotificationFilter;
import org.eclipse.emf.transaction.Transaction;
import org.eclipse.emf.transaction.TransactionalCommandStack;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.impl.TransactionalEditingDomainImpl;
import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.databinding.swt.ISWTObservable;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.viewers.IPostSelectionProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IStorageEditorInput;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.dialogs.SaveAsDialog;
import org.eclipse.ui.editors.text.TextEditor;
import org.eclipse.ui.forms.editor.FormEditor;
import org.eclipse.ui.forms.editor.IFormPage;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.ide.IGotoMarker;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.MultiPageEditorPart;
import org.eclipse.ui.part.MultiPageEditorSite;
import org.eclipse.ui.progress.WorkbenchJob;
import org.eclipse.ui.statushandlers.StatusManager;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import org.xml.sax.InputSource;
/**
* The Class SCAFormEditor.
*/
public abstract class SCAFormEditor extends FormEditor implements IEditingDomainProvider, IMenuListener, IExecutableExtension, IViewerProvider, IGotoMarker {
/**
* @since 6.0
*/
public static int getFieldBindingDelay() {
return 200;
}
/**
* Heavily inspired by code in the GEF LogicEditor example
*
* @since 6.0
*/
public class ResourceTracker implements IResourceChangeListener, IResourceDeltaVisitor {
private final Set<IResource> trackedResources;
public ResourceTracker() {
super();
this.trackedResources = new HashSet<IResource>();
}
public ResourceTracker(final IResource[] loadedResources) {
super();
this.trackedResources = new HashSet<IResource>(Arrays.asList(loadedResources));
}
public void addTrackedResource(final IResource resource) {
this.trackedResources.add(resource);
}
public void removeTrackedResource(final IResource resource) {
this.trackedResources.remove(resource);
}
public void clearTrackedResources() {
this.trackedResources.clear();
}
@Override
public void resourceChanged(final IResourceChangeEvent event) {
final IResourceDelta delta = event.getDelta();
switch (event.getType()) {
case IResourceChangeEvent.POST_CHANGE:
case IResourceChangeEvent.PRE_CLOSE:
case IResourceChangeEvent.PRE_DELETE:
if (delta != null) {
if (Display.getCurrent() == null) {
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
try {
delta.accept(ResourceTracker.this);
} catch (final CoreException e) {
// PASS
}
}
});
} else {
try {
delta.accept(this);
} catch (final CoreException e) {
// PASS
}
}
}
break;
default:
break;
}
}
@Override
public boolean visit(final IResourceDelta delta) throws CoreException {
if (reloading) {
return false;
}
if ((delta == null) || (!this.trackedResources.contains(delta.getResource()))) {
return true;
}
switch (delta.getKind()) {
case IResourceDelta.REMOVED:
if ((IResourceDelta.MOVED_TO & delta.getFlags()) == 0) { // deleted
final IFile resource = ResourcesPlugin.getWorkspace().getRoot().getFile(delta.getFullPath());
SCAFormEditor.this.resourceDeleted(resource);
} else { // moved or renamed
final IFile to = ResourcesPlugin.getWorkspace().getRoot().getFile(delta.getMovedToPath());
SCAFormEditor.this.resourceMoved(delta.getResource(), to);
}
break;
case IResourceDelta.CHANGED:
// Ignore changes if they are only to markers, or if the changes aren't for a file
if (delta.getFlags() == IResourceDelta.MARKERS) {
break;
}
if (!(delta.getResource() instanceof IFile)) {
break;
}
final IFile newFile = (IFile) delta.getResource();
// If the resource has been changed on disk and the editor is dirty we will prompt the user before
// blowing away its changes.
if (SCAFormEditor.this.isDirty() && !SCAFormEditor.this.editorSaving) {
boolean confirmOverwrite = MessageDialog.openConfirm(SCAFormEditor.this.getSite().getShell(), "File Changed", "The file '"
+ delta.getResource().getFullPath().toOSString()
+ "' has been changed on the file system. Do you want to replace the editor contents with these changes?");
SCAFormEditor.this.setFocus();
if (confirmOverwrite) {
SCAFormEditor.this.resourceChanged(newFile, delta);
// Since the document gets changed within the resourceChanged function, the document will be
// marked dirty even though the document matches what is on disk. Currently I cannot figure out
// a good way to get rid of this dirty flag. It's a small bug that should not happen often
// though.
}
}
// If the editor is not dirty and the editor is not in the middle of saving then we'll take the
// changes. This will cause the editor to appear dirty erroneously as mentioned in the note above.
if (!SCAFormEditor.this.isDirty() && !SCAFormEditor.this.editorSaving) {
SCAFormEditor.this.resourceChanged(newFile, delta);
}
break;
default:
break;
}
return false;
}
}
/**
* @since 6.0
*/
private ResourceTracker resourceTracker = new ResourceTracker();
private boolean reloading = false;
/**
* Updates the OutlinePage selection.
*/
public class SCAFormEditorChangeListener implements ISelectionChangedListener {
/**
* Installs this selection changed listener with the given selection provider. If the selection provider is a
* post selection provider, post selection changed events are the preferred choice, otherwise normal selection
* changed events are requested.
*
* @param selectionProvider the selection provider
*/
public void install(final ISelectionProvider selectionProvider) {
if (selectionProvider == null) {
return;
}
if (selectionProvider instanceof IPostSelectionProvider) {
final IPostSelectionProvider provider = (IPostSelectionProvider) selectionProvider;
provider.addPostSelectionChangedListener(this);
} else {
selectionProvider.addSelectionChangedListener(this);
}
}
/**
* {@inheritDoc}
*/
@Override
public void selectionChanged(final SelectionChangedEvent event) {
if (RedhawkUiActivator.getDefault().getPreferenceStore().getBoolean("ToggleLinkWithEditorAction.isChecked")) {
if (getFormOutline() != null) {
getFormOutline().setSelection(event.getSelection());
}
}
}
/**
* Removes this selection changed listener from the given selection provider.
*
* @param selectionProvider the selection provider
*/
public void uninstall(final ISelectionProvider selectionProvider) {
if (selectionProvider == null) {
return;
}
if (selectionProvider instanceof IPostSelectionProvider) {
final IPostSelectionProvider provider = (IPostSelectionProvider) selectionProvider;
provider.removePostSelectionChangedListener(this);
} else {
selectionProvider.removeSelectionChangedListener(this);
}
}
}
private static final String F_DIALOG_EDITOR_SECTION_KEY = "pde-form-editor"; //$NON-NLS-1$
private WorkbenchJob updateTitleJob;
@Override
protected void setSite(final org.eclipse.ui.IWorkbenchPartSite site) {
this.updateTitleJob = new WorkbenchJob(site.getShell().getDisplay(), "UpdateTitle") {
{
setUser(false);
setSystem(true);
}
@Override
public IStatus runInUIThread(final IProgressMonitor monitor) {
firePropertyChange(IWorkbenchPart.PROP_TITLE);
return Status.OK_STATUS;
}
};
super.setSite(site);
}
/**
* The editor selection changed listener.
*/
private SCAFormEditorChangeListener fEditorSelectionChangedListener;
private Clipboard clipboard;
private IContentOutlinePage fFormOutline;
private SCAMultiPageContentOutline fContentOutline;
private int fLastActivePageIndex;
private boolean fLastDirtyState;
private boolean handledStructuredModelChange;
/**
* Listen for changes to command stack and attempt to handle the change.
*/
private CommandStackListener commandStackListener = new CommandStackListener() {
@Override
public void commandStackChanged(final EventObject event) {
if (Display.getCurrent() != null) {
handleStackChanged(event);
} else if (getContainer() != null && !getContainer().isDisposed()) {
getContainer().getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
if (getContainer() != null && !getContainer().isDisposed()) {
handleStackChanged(event);
}
}
});
}
}
private void handleStackChanged(EventObject event) {
handleStructuredModelChange(event);
firePropertyChange(IEditorPart.PROP_DIRTY);
final Command mostRecentCommand = ((CommandStack) event.getSource()).getMostRecentCommand();
if (mostRecentCommand != null && mostRecentCommand.getAffectedObjects() != null && !mostRecentCommand.getAffectedObjects().isEmpty()) {
setSelectionToViewer(mostRecentCommand.getAffectedObjects());
}
}
};
/**
* This keeps track of the editing domain that is used to track all changes to the model.
*/
private EditingDomain editingDomain;
/** The outline cache. */
private final Map<IEditorPart, IContentOutlinePage> outlineCache = new HashMap<IEditorPart, IContentOutlinePage>();
private final DataBindingContext bindingContext;
private ValidatingEContentAdapter validator;
private String id;
private boolean disposed;
private Resource mainResource;
private final Map<Resource, IDocument> resourceToDocumentMap = new HashMap<Resource, IDocument>();
/**
* @since 8.0
*/
protected boolean editorSaving;
private RefreshIdlLibraryJob reloadLibraryJob;
/**
* The Class SCAMultiPageEditorSite.
*/
private static class SCAMultiPageEditorSite extends MultiPageEditorSite {
/**
* Instantiates a new sCA multi page editor site.
*
* @param multiPageEditor the multi page editor
* @param editor the editor
*/
public SCAMultiPageEditorSite(final MultiPageEditorPart multiPageEditor, final IEditorPart editor) {
super(multiPageEditor, editor);
}
/**
* {@inheritDoc}
*/
@Override
public IWorkbenchPart getPart() {
return getMultiPageEditor();
}
@Override
protected void handleSelectionChanged(SelectionChangedEvent event) {
// On occasion, viewers that are not visible may still emit selection change events due to model updates
// (mostly StructuredTextEditors); from the perspective of the form editor, these selection events should
// be ignored, otherwise the properties view may unexpectedly change contents.
if (isSelectionSourceVisible(event)) {
super.handleSelectionChanged(event);
}
}
@Override
protected void handlePostSelectionChanged(SelectionChangedEvent event) {
// See above.
if (isSelectionSourceVisible(event)) {
super.handlePostSelectionChanged(event);
}
}
private boolean isSelectionSourceVisible(SelectionChangedEvent event) {
if (event.getSource() instanceof Viewer) {
Viewer viewer = (Viewer) event.getSource();
Control control = viewer.getControl();
if (!control.isVisible()) {
return false;
}
}
return true;
}
}
/**
* Instantiates a new sCA form editor.
*/
public SCAFormEditor() {
this.bindingContext = new EMFDataBindingContext();
}
/**
* Handles activation of the editor or it's associated views.
*/
protected void handleActivate() {
// Recompute the read only state.
//
if (this.editingDomain instanceof AdapterFactoryEditingDomain) {
if (((AdapterFactoryEditingDomain) this.editingDomain).getResourceToReadOnlyMap() != null) {
((AdapterFactoryEditingDomain) this.editingDomain).getResourceToReadOnlyMap().clear();
// Refresh any actions that may become enabled or disabled.
//
getSite().getSelectionProvider().setSelection(getSite().getSelectionProvider().getSelection());
}
}
}
/**
* This sets up the editing domain for the model editor.
*/
protected void initializeEditingDomain() {
TransactionalEditingDomain domain = createEditingDomain();
final Map<String, Boolean> myOptions = new HashMap<String, Boolean>();
myOptions.put(Transaction.OPTION_NO_VALIDATION, Boolean.TRUE);
if (domain instanceof TransactionalEditingDomainImpl) {
((TransactionalEditingDomainImpl) domain).setDefaultTransactionOptions(myOptions);
}
final NotificationFilter resourceModifiedFilter = NotificationFilter.createNotifierFilter(domain.getResourceSet()).and(
NotificationFilter.createEventTypeFilter(Notification.ADD)).and(
NotificationFilter.createFeatureFilter(ResourceSet.class, ResourceSet.RESOURCE_SET__RESOURCES));
domain.getResourceSet().eAdapters().add(new Adapter() {
private Notifier myTarget;
@Override
public Notifier getTarget() {
return this.myTarget;
}
@Override
public boolean isAdapterForType(final Object type) {
return false;
}
@Override
public void notifyChanged(final Notification notification) {
if (resourceModifiedFilter.matches(notification)) {
final Object value = notification.getNewValue();
if (value instanceof Resource) {
((Resource) value).setTrackingModification(true);
}
}
}
@Override
public void setTarget(final Notifier newTarget) {
this.myTarget = newTarget;
}
});
// Add a listener to set the most recent command's affected objects to
// be the selection of the viewer with focus.
//
domain.getCommandStack().addCommandStackListener(this.commandStackListener);
this.editingDomain = domain;
}
/**
* @since 8.0
*/
protected TransactionalEditingDomain createEditingDomain() {
TransactionalEditingDomain domain = TransactionalEditingDomain.Registry.INSTANCE.getEditingDomain(getEditingDomainId());
if (domain == null) {
domain = TransactionalEditingDomain.Factory.INSTANCE.createEditingDomain();
domain.setID(getEditingDomainId());
// Create an adapter factory that yields item providers.
//
final ComposedAdapterFactory localAdapterFactory = new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE);
localAdapterFactory.addAdapterFactory(new ResourceItemProviderAdapterFactory());
localAdapterFactory.addAdapterFactory(getSpecificAdapterFactory());
localAdapterFactory.addAdapterFactory(new ReflectiveItemProviderAdapterFactory());
((AdapterFactoryEditingDomain) domain).setAdapterFactory(localAdapterFactory);
}
return domain;
}
/**
* Provide access to the command stack listener so that subclasses may remove if so desired.
*
* @return the {@link CommandStackListener} associated with this editors editing domain
* @since 4.0
*/
protected CommandStackListener getCommandStackListener() {
return this.commandStackListener;
}
/**
* @return The ID of the Editing Domain used by this editor
*/
public abstract String getEditingDomainId();
/**
* @return Adapter Factory Specific to this editor
*/
protected abstract AdapterFactory getSpecificAdapterFactory();
/**
* We must override nested site creation so that we properly pass the source editor contributor when asked.
*
* @param editor the editor
* @return the i editor site
*/
@Override
protected IEditorSite createSite(final IEditorPart editor) {
return new SCAMultiPageEditorSite(this, editor);
}
/**
* Gets the context manager.
*
* @return the context manager
*/
@Override
public EditingDomain getEditingDomain() {
return this.editingDomain;
}
/**
* {@inheritDoc}
*/
@Override
protected FormToolkit createToolkit(final Display display) {
// Create a toolkit that shares colors between editors.
return new FormToolkit(RedhawkUiActivator.getDefault().getFormColors(display));
}
/*
* When subclassed, don't forget to call 'super'
*/
/**
* {@inheritDoc}
*/
@Override
protected void createPages() {
this.clipboard = new Clipboard(getContainer().getDisplay());
super.createPages();
final int pageIndex = computeInitialPageId();
if (pageIndex >= 0 && pageIndex < getPageCount()) {
setActivePage(pageIndex);
}
updateTitle();
final Notifier obj = getRootValidationNotifier();
this.validator = new ValidatingEContentAdapter(this, obj);
if (obj != null) {
obj.eAdapters().add(this.validator);
this.validate();
}
// Ensures that this editor will only display the page's tab
// area if there are more than one page
//
getContainer().addControlListener(new ControlAdapter() {
private boolean guard = false;
@Override
public void controlResized(final ControlEvent event) {
if (!this.guard) {
this.guard = true;
hideTabs();
this.guard = false;
}
}
});
}
/**
* @return
*/
protected Notifier getRootValidationNotifier() {
return this.getMainResource();
}
/**
* If there is just one page in the multi-page editor part, this hides the single tab at the bottom. <!--
* begin-user-doc --> <!-- end-user-doc -->
*/
protected void hideTabs() {
if (getPageCount() == 1) {
setPageText(0, "");
if (getContainer() instanceof CTabFolder) {
((CTabFolder) getContainer()).setTabHeight(1);
final Point point = getContainer().getSize();
getContainer().setSize(point.x, point.y + 6); // SUPPRESS CHECKSTYLE MagicNumber
}
}
}
/**
* If there is more than one page in the multi-page editor part, this shows the tabs at the bottom. <!--
* begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
protected void showTabs() {
if (getPageCount() > 1) {
if (getContainer() instanceof CTabFolder) {
((CTabFolder) getContainer()).setTabHeight(SWT.DEFAULT);
final Point point = getContainer().getSize();
getContainer().setSize(point.x, point.y - 6); // SUPPRESS CHECKSTYLE MagicNumber
}
}
}
/**
* {@inheritDoc}
*/
@Override
protected void pageChange(final int newPageIndex) {
super.pageChange(newPageIndex);
updateContentOutline(newPageIndex);
this.fLastActivePageIndex = newPageIndex;
final Viewer viewer = getViewer();
if (viewer != null) {
this.setSelection(viewer.getSelection());
} else {
this.setSelection(new StructuredSelection());
}
validate();
}
/**
* {@inheritDoc}
*/
@Override
public void setFocus() {
super.setFocus();
final IFormPage page = getActivePageInstance();
// Could be done on setActive in PDEFormPage;
// but setActive only handles page switches and not focus events
if ((page != null) && (page instanceof ScaFormPage)) {
((ScaFormPage) page).updateFormSelection();
}
}
/**
* Gets the clipboard.
*
* @return the clipboard
* @since 5.0
*/
public Clipboard getClipboard() {
return this.clipboard;
}
/**
* Gets the contributor.
*
* @return the contributor
*/
public ScaMultipageActionBarContributor getActionBarContributor() {
return (ScaMultipageActionBarContributor) getEditorSite().getActionBarContributor();
}
/**
* Compute initial page id.
*
* @return the string
*/
protected int computeInitialPageId() {
int firstPageId = 0;
final String storedFirstPageId = loadDefaultPage();
if (storedFirstPageId != null) {
try {
firstPageId = Integer.valueOf(storedFirstPageId);
} catch (final NumberFormatException e) {
firstPageId = 0;
}
}
if (firstPageId >= getPageCount()) {
firstPageId = 0;
}
return firstPageId;
}
/**
* Update title.
*/
public void updateTitle() {
this.updateTitleJob.schedule();
}
/**
* Gets the title property.
*
* @return the title property
*/
public String getTitleProperty() {
return ""; //$NON-NLS-1$
}
/**
* {@inheritDoc}
*/
@Override
public void doSave(final IProgressMonitor monitor) {
try {
this.editorSaving = true;
commitPages(true);
monitor.beginTask("Saving " + this.getTitle(), this.getPageCount() + 2);
internalDoValidate(new SubProgressMonitor(monitor, 1));
for (int i = 0; i < this.getPageCount(); i++) {
final IEditorPart part = this.getEditor(i);
if (part != null && part.isDirty()) {
part.doSave(new SubProgressMonitor(monitor, 1));
} else {
monitor.worked(1);
}
}
if (isDirty()) {
emfDoSave(new SubProgressMonitor(monitor, 1));
}
editorDirtyStateChanged();
} catch (final OperationCanceledException e) {
// PASS
} finally {
monitor.done();
this.editorSaving = false;
}
}
/**
* @since 6.0
*/
protected void closeEditor(final boolean save) {
getSite().getPage().closeEditor(this, save);
}
/**
* This is for implementing {@link IEditorPart} and simply saves the model file.
*
* @param progressMonitor the progress monitor
* @since 2.3
*/
protected void emfDoSave(final IProgressMonitor progressMonitor) {
// Save only resources that have actually changed.
//
final Map<Object, Object> saveOptions = new HashMap<Object, Object>();
saveOptions.put(Resource.OPTION_SAVE_ONLY_IF_CHANGED, Resource.OPTION_SAVE_ONLY_IF_CHANGED_MEMORY_BUFFER);
// Do the work within an operation because this is a long running
// activity that modifies the workbench.
//
final WorkspaceModifyOperation operation = new WorkspaceModifyOperation() {
// This is the method that gets invoked when the operation runs.
//
@Override
public void execute(final IProgressMonitor monitor) throws CoreException {
// Save the resources to the file system.
//
for (final Resource resource : SCAFormEditor.this.editingDomain.getResourceSet().getResources()) {
if (isPersisted(resource) && !SCAFormEditor.this.editingDomain.isReadOnly(resource)) {
// Lastly, check to make sure this resource is not only local to the current workspace
// but is also local to the project we're currently saving. This fixes bug # 266
if (isPersisted(resource) && isLocal(resource)) {
try {
resource.save(saveOptions);
} catch (final Exception exception) { // SUPPRESS CHECKSTYLE Logged Catch all exception
throw new CoreException(new Status(IStatus.ERROR, RedhawkUiActivator.getPluginId(), "Failed to save resource: " + resource,
exception));
}
}
}
}
}
/**
* Checks to see if the given resource is within the same project as the SCAFormEditor.
* This fixes bug # 266
* @param resource The resource to be checked
* @return
*/
private boolean isLocal(final Resource resource) {
// If the resource isn't located in the workspace it isn't local
if (!resource.getURI().isPlatformResource()) {
return false;
}
// Get the file for the referenced resource
IPath pathToResource = new Path(resource.getURI().toPlatformString(true));
IFile resourceFile = ResourcesPlugin.getWorkspace().getRoot().getFile(pathToResource);
// Check the file's project against the SCA Form Editor's scd file's project.
if (resourceFile != null && resourceFile.getProject() != null) {
if (SCAFormEditor.this.getEditorInput() instanceof IFileEditorInput) {
IFile localFile = ((IFileEditorInput) SCAFormEditor.this.getEditorInput()).getFile();
if (localFile != null) {
if (localFile.getProject().equals(resourceFile.getProject())) {
return true;
}
}
}
}
return false;
}
};
try {
operation.run(progressMonitor);
// Refresh the necessary state.
//
((BasicCommandStack) this.editingDomain.getCommandStack()).saveIsDone();
} catch (final Exception exception) { // SUPPRESS CHECKSTYLE Logged Catch all exception
// Something went wrong that shouldn't.
//
StatusManager.getManager().handle(
new Status(IStatus.ERROR, RedhawkUiActivator.getPluginId(), "Error occured while attempting to save.", exception),
StatusManager.SHOW | StatusManager.LOG);
}
}
/**
* This returns whether something has been persisted to the URI of the specified resource. The implementation uses
* the URI converter from the editor's resource set to try to open an input stream.
*
* @param resource the resource
* @return true, if checks if is persisted
* @since 2.1
*/
public boolean isPersisted(final Resource resource) {
// If the resource isn't located in the workspace it isn't local
if (resource != null && resource.getURI() != null && resource.getURI().isPlatformResource()) {
// Get the file for the referenced resource
IPath pathToResource = new Path(resource.getURI().toPlatformString(true));
IFile resourceFile = ResourcesPlugin.getWorkspace().getRoot().getFile(pathToResource);
// Check the file's project against the SCA Form Editor's scd file's project.
if (resourceFile != null && resourceFile.getProject() != null) {
if (SCAFormEditor.this.getEditorInput() instanceof IFileEditorInput) {
IFile localFile = ((IFileEditorInput) SCAFormEditor.this.getEditorInput()).getFile();
if (localFile != null) {
if (localFile.getProject().equals(resourceFile.getProject())) {
return true;
}
}
}
}
return false;
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
public void gotoMarker(final IMarker marker) {
final String uriAttribute = marker.getAttribute(EValidator.URI_ATTRIBUTE, null);
final int featureID = marker.getAttribute(AdvancedEObjectValidator.FEATURE_ID, AdvancedEObjectValidator.DEFAULT_ID);
if (uriAttribute != null) {
final URI uri = URI.createURI(uriAttribute);
final EObject eObject = this.editingDomain.getResourceSet().getEObject(uri, true);
if (eObject != null) {
for (final Object o : this.bindingContext.getBindings()) {
final Binding binding = (Binding) o;
EditingDomainEObjectObservableValue emfObservable = null;
ISWTObservable swtObservable = null;
final IObservable model = binding.getModel();
final IObservable target = binding.getTarget();
if (model instanceof EditingDomainEObjectObservableValue && target instanceof ISWTObservable) {
emfObservable = (EditingDomainEObjectObservableValue) model;
swtObservable = (ISWTObservable) target;
} else if (binding.getTarget() instanceof EditingDomainEObjectObservableValue && model instanceof ISWTObservable) {
swtObservable = (ISWTObservable) model;
emfObservable = (EditingDomainEObjectObservableValue) target;
}
if (emfObservable != null && swtObservable != null) {
if (this.selectFeature(emfObservable, swtObservable, eObject, featureID)) {
break;
}
}
}
}
}
}
/**
* Sets focus on the correct control.
*
* @param emfObservable
* @param swtObservable
* @param object
* @param featureID
* @return
*/
private boolean selectFeature(final EditingDomainEObjectObservableValue emfObservable, final ISWTObservable swtObservable, final EObject object,
final int featureID) {
boolean retVal = false;
final Object observed = emfObservable.getObserved();
if (emfObservable.getValueType() instanceof EStructuralFeature) {
final int myId = ((EStructuralFeature) emfObservable.getValueType()).getFeatureID();
if (object == observed) {
if (featureID == myId) {
if (swtObservable.getWidget() instanceof Control) {
final Control control = (Control) swtObservable.getWidget();
control.setFocus();
retVal = true;
}
}
}
}
return retVal;
}
/**
* This is the method called to load a resource into the editing domain's resource set based on the editor's input.
*/
protected void createModel() {
final URI resourceURI = EditUIUtil.getURI(getEditorInput());
// For safety we'll decode the URI to make sure escape sequences have been correctly represented
String decodedURIString = URI.decode(resourceURI.toString());
final URI decodedURI = URI.createURI(decodedURIString);
Exception exception = null;
try {
// Load the resource through the editing domain.
//
if (Display.getCurrent() != null) {
ProgressMonitorDialog dialog = new ProgressMonitorDialog(Display.getCurrent().getActiveShell());
dialog.run(true, true, new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
try {
monitor.beginTask("Loading XML...", IProgressMonitor.UNKNOWN);
mainResource = CorbaUtils.invoke(new Callable<Resource>() {
@Override
public Resource call() throws Exception {
return editingDomain.getResourceSet().getResource(decodedURI, true);
}
}, monitor);
} catch (CoreException e) {
throw new InvocationTargetException(e);
}
}
});
} else {
mainResource = editingDomain.getResourceSet().getResource(decodedURI, true);
}
} catch (final Exception e) { // SUPPRESS CHECKSTYLE Logged Catch all exception
exception = e;
this.mainResource = this.editingDomain.getResourceSet().getResource(decodedURI, false);
}
if (exception != null) {
StatusManager.getManager().handle(
new Status(IStatus.ERROR, RedhawkUiActivator.getPluginId(), "Errors occured while loading the main resource of the editor.", exception),
StatusManager.SHOW | StatusManager.LOG);
}
}
/**
* @return the mainResource
*/
public Resource getMainResource() {
return this.mainResource;
}
/**
* This also changes the editor's input.
*/
@Override
public void doSaveAs() {
if (!isSaveAsAllowed()) {
throw new UnsupportedOperationException("Save as not supported");
}
final SaveAsDialog saveAsDialog = new SaveAsDialog(getSite().getShell());
saveAsDialog.open();
final IPath path = saveAsDialog.getResult();
if (path != null) {
final IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
if (file != null) {
doSaveAs(URI.createPlatformResourceURI(file.getFullPath().toString(), true), new FileEditorInput(file));
}
}
}
/**
* Do save as. This method should be overridden.
*
* @param createPlatformResourceURI the create platform resource uri
* @param fileEditorInput the file editor input
* @since 5.0
*/
protected void doSaveAs(final URI createPlatformResourceURI, final FileEditorInput fileEditorInput) {
throw new UnsupportedOperationException("Save as not supported");
}
/**
* {@inheritDoc}
*/
@Override
public boolean isSaveAsAllowed() {
return false;
}
/**
*
*/
private void storeDefaultPage() {
final IEditorInput input = getEditorInput();
final String pageId = Integer.toString(this.fLastActivePageIndex);
if (pageId == null) {
return;
}
if (input instanceof IFileEditorInput) {
// Triggered by opening a file in the workspace
// e.g. From the Package Explorer View
setPropertyEditorPageKey((IFileEditorInput) input, pageId);
} else if (input instanceof IStorageEditorInput) {
// Triggered by opening a file NOT in the workspace
// e.g. From the Plug-in View
setDialogEditorPageKey(pageId);
}
}
/**
* Sets the dialog editor page key.
*
* @param pageID the page id
*/
protected void setDialogEditorPageKey(final String pageID) {
// Use one global setting for all files belonging to a given editor
// type. Use the editor ID as the key.
// Could use the storage editor input to get the underlying file
// and use it as a unique key; but, the dialog settings file will
// grow out of control and we do not need that level of granularity
final IDialogSettings section = getSettingsSection();
section.put(getEditorID(), pageID);
}
/**
* Gets the dialog editor page key.
*
* @return the dialog editor page key
*/
protected String getDialogEditorPageKey() {
// Use one global setting for all files belonging to a given editor
// type. Use the editor ID as the key.
// Could use the storage editor input to get the underlying file
// and use it as a unique key; but, the dialog settings file will
// grow out of control and we do not need that level of granularity
final IDialogSettings section = getSettingsSection();
return section.get(getEditorID());
}
/**
* Gets the editor id.
*
* @return the editor id
*/
protected final String getEditorID() {
return this.id;
}
/**
* Sets the property editor page key.
*
* @param input the input
* @param pageId the page id
* @since 5.0
*/
protected void setPropertyEditorPageKey(final IFileEditorInput input, final String pageId) {
// We are using the file itself to persist the editor page key property
// The value persists even after the editor is closed
final IFile file = input.getFile();
try {
// Set the editor page ID as a persistent property on the file
file.setPersistentProperty(ScaIdeConstants.PROPERTY_EDITOR_PAGE_KEY, pageId);
} catch (final CoreException e) {
// PASS
}
}
/**
* Load default page.
*
* @return the string
*/
private String loadDefaultPage() {
final IEditorInput input = getEditorInput();
if (input instanceof IFileEditorInput) {
// Triggered by opening a file in the workspace
// e.g. From the Package Explorer View
return getPropertyEditorPageKey((IFileEditorInput) input);
} else if (input instanceof IStorageEditorInput) {
// Triggered by opening a file NOT in the workspace
// e.g. From the Plug-in View
return getDialogEditorPageKey();
}
return getDefaultPageKey();
}
/**
* @since 8.0
*/
protected String getDefaultPageKey() {
return null;
}
/**
* Gets the property editor page key.
*
* @param input the input
* @return the property editor page key
* @since 5.0
*/
protected String getPropertyEditorPageKey(final IFileEditorInput input) {
// We are using the file itself to persist the editor page key property
// The value persists even after the editor is closed
final IFile file = input.getFile();
// Get the persistent editor page key from the file
try {
return file.getPersistentProperty(ScaIdeConstants.PROPERTY_EDITOR_PAGE_KEY);
} catch (final CoreException e) {
return null;
}
}
/**
* {@inheritDoc}
*/
@Override
public void dispose() {
this.disposed = true;
storeDefaultPage();
if (this.fEditorSelectionChangedListener != null) {
this.fEditorSelectionChangedListener.uninstall(getSite().getSelectionProvider());
this.fEditorSelectionChangedListener = null;
}
setSelection(new StructuredSelection());
if (this.clipboard != null) {
this.clipboard.dispose();
this.clipboard = null;
}
if (getEditingDomain() instanceof AdapterFactoryEditingDomain) {
if (((AdapterFactoryEditingDomain) this.editingDomain).getAdapterFactory() instanceof IDisposable) {
((IDisposable) ((AdapterFactoryEditingDomain) this.editingDomain).getAdapterFactory()).dispose();
}
}
if (this.commandStackListener != null) {
if (this.editingDomain != null) {
if (this.editingDomain.getCommandStack() != null) {
this.editingDomain.getCommandStack().removeCommandStackListener(this.commandStackListener);
}
}
this.commandStackListener = null;
}
this.editingDomain = null;
this.outlineCache.clear();
// Waveform Explorer editor input is ScaFileStoreEditorInput, ignore this
if (getEditorInput() instanceof IFileEditorInput) {
final IFile file = ((IFileEditorInput) getEditorInput()).getFile();
file.getWorkspace().removeResourceChangeListener(this.resourceTracker);
}
if (this.resourceTracker != null) {
this.resourceTracker.clearTrackedResources();
this.resourceTracker = null;
}
super.dispose();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isDirty() {
this.fLastDirtyState = computeDirtyState();
return this.fLastDirtyState;
}
/**
* Compute dirty state.
*
* @return true, if successful
* @since 8.0
*/
protected boolean computeDirtyState() {
if ((this.editingDomain != null) && ((BasicCommandStack) this.editingDomain.getCommandStack()).isSaveNeeded()) {
return true;
}
if (this.editingDomain != null) {
return super.isDirty();
}
return false;
}
/**
* Gets the last dirty state.
*
* @return the last dirty state
*/
public boolean getLastDirtyState() {
return this.fLastDirtyState;
}
/**
* Gets the settings section.
*
* @return the settings section
*/
private IDialogSettings getSettingsSection() {
// Store global settings that will persist when the editor is closed
// in the dialog settings (This is cheating)
// Get the dialog settings
final IDialogSettings root = RedhawkUiActivator.getDefault().getDialogSettings();
// Get the dialog section reserved for PDE form editors
IDialogSettings section = root.getSection(SCAFormEditor.F_DIALOG_EDITOR_SECTION_KEY);
// If the section is not defined, define it
if (section == null) {
section = root.addNewSection(SCAFormEditor.F_DIALOG_EDITOR_SECTION_KEY);
}
return section;
}
/**
* Sets the selection.
*
* @param selection the new selection
*/
public void setSelection(final ISelection selection) {
if (getSite() != null && getSite().getSelectionProvider() != null) {
getSite().getSelectionProvider().setSelection(selection);
}
}
/**
* Gets the selection.
*
* @return the selection
*/
public ISelection getSelection() {
return getSite().getSelectionProvider().getSelection();
}
/**
* {@inheritDoc}
*/
@Override
public <T> T getAdapter(final Class<T> key) {
if (key.equals(IContentOutlinePage.class)) {
return key.cast(getContentOutline());
}
if (key.equals(IGotoMarker.class)) {
return key.cast(this);
}
return super.getAdapter(key);
}
/**
* Gets the content outline.
*
* @return the content outline
*/
public SCAMultiPageContentOutline getContentOutline() {
if (this.fContentOutline == null || this.fContentOutline.isDisposed()) {
this.fContentOutline = new SCAMultiPageContentOutline(this);
updateContentOutline(getActivePage());
}
return this.fContentOutline;
}
/**
* Gets the form outline.
*
* @return outline page or null
* @since 6.0
*/
public IContentOutlinePage getFormOutline() {
if (this.fFormOutline == null) {
this.fFormOutline = createContentOutline();
if (this.fFormOutline != null) {
this.fEditorSelectionChangedListener = new SCAFormEditorChangeListener();
this.fEditorSelectionChangedListener.install(getSite().getSelectionProvider());
}
}
return this.fFormOutline;
}
/**
* Creates the content outline.
*
* @return the i sortable content outline page
*/
protected abstract IContentOutlinePage createContentOutline();
/**
* Update content outline.
*
* @param index the index
*/
private void updateContentOutline(final int index) {
if (this.fContentOutline == null) {
return;
}
IContentOutlinePage outline = null;
final IEditorPart editor = this.getEditor(index);
if (editor != null) {
outline = this.outlineCache.get(editor);
if (outline == null) {
final Object adapter = editor.getAdapter(IContentOutlinePage.class);
if (adapter instanceof IContentOutlinePage) {
outline = (IContentOutlinePage) adapter;
this.outlineCache.put(editor, outline);
}
}
}
if (outline == null) {
outline = getFormOutline();
if (outline != null && outline instanceof FormOutlinePage) {
((FormOutlinePage) outline).refresh();
}
}
this.fContentOutline.setPageActive(outline);
}
/**
* {@inheritDoc}
*/
@Override
public IFormPage setActivePage(final String pageId) {
final IFormPage page = super.setActivePage(pageId);
if (page != null) {
updateContentOutline(page.getIndex());
}
return page;
}
/**
* {@inheritDoc}
*/
@Override
public void init(final IEditorSite site, final IEditorInput input) throws PartInitException {
super.init(site, input);
// ResourcesPlugin.getWorkspace().addResourceChangeListener(this.resourceChangeListener,
// IResourceChangeEvent.POST_CHANGE);
}
@Override
protected void addPages() {
// TODO Auto-generated method stub
}
/**
* Add resource tracking to the provided input. Sub-classes may override but should call super.setInput().
* Sub-classes may add other resources to track via the getResourceTracker().addTrackedResource()
*/
@Override
protected void setInput(final IEditorInput input) {
IFile file = null;
if (input instanceof IFileEditorInput) {
file = ((IFileEditorInput) input).getFile();
}
IFile previousFile = null;
if ((getEditorInput() != null) && (getEditorInput() instanceof IFileEditorInput)) {
previousFile = ((IFileEditorInput) getEditorInput()).getFile();
}
// Remove the previous tracker...not technically necessary but
// implemented for the sake of completeness
if (previousFile != null) {
this.resourceTracker.clearTrackedResources();
previousFile.getWorkspace().removeResourceChangeListener(this.resourceTracker);
}
initializeEditingDomain();
super.setInput(input);
createModel();
if (file != null) {
this.resourceTracker.addTrackedResource(file);
file.getWorkspace().addResourceChangeListener(this.resourceTracker);
}
}
/**
* Contribute to toolbar.
*
* @param manager the manager
*/
public void contributeToToolbar(final IToolBarManager manager) {
}
/**
* This creates a context menu for the viewer and adds a listener as well registering the menu for extension.
*
* @param viewer the viewer
*/
protected void createContextMenuFor(final StructuredViewer viewer) {
final MenuManager contextMenu = new MenuManager("#PopUp");
contextMenu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
contextMenu.setRemoveAllWhenShown(true);
contextMenu.addMenuListener(this);
final Menu menu = contextMenu.createContextMenu(viewer.getControl());
viewer.getControl().setMenu(menu);
getSite().registerContextMenu(contextMenu, new UnwrappingSelectionProvider(viewer));
final int dndOperations = DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK;
final Transfer[] transfers = new Transfer[] { LocalTransfer.getInstance() };
viewer.addDragSupport(dndOperations, transfers, new ViewerDragAdapter(viewer));
viewer.addDropSupport(dndOperations, transfers, new EditingDomainViewerDropAdapter(getEditingDomain(), viewer));
}
/**
* This implements {@link org.eclipse.jface.action.IMenuListener} to help fill the context menus with contributions
* from the Edit menu.
*
* @param menuManager the menu manager
*/
@Override
public void menuAboutToShow(final IMenuManager menuManager) {
((IMenuListener) getEditorSite().getActionBarContributor()).menuAboutToShow(menuManager);
}
/**
* {@inheritDoc}
*/
@Override
public void setInitializationData(final IConfigurationElement config, final String propertyName, final Object data) {
super.setInitializationData(config, propertyName, data);
this.id = config.getAttribute("id");
}
/**
* @return
*/
public DataBindingContext getDataBindingContext() {
return this.bindingContext;
}
/**
* @return
*/
public AdapterFactory getAdapterFactory() {
if (getEditingDomain() instanceof AdapterFactoryEditingDomain) {
return ((AdapterFactoryEditingDomain) getEditingDomain()).getAdapterFactory();
}
return null;
}
/**
* @since 8.0
*/
public void validate() {
validate(null);
}
/**
* @since 8.0
*/
public void validate(JobChangeAdapter adapter) {
if (this.validator != null) {
Display display = null;
if (getSite() != null) {
display = getSite().getShell().getDisplay();
}
final WorkbenchJob job = new WorkbenchJob(display, "Validating editor: " + this.getTitle()) {
@Override
public boolean shouldRun() {
return super.shouldRun() && !isDisposed();
}
@Override
public IStatus runInUIThread(final IProgressMonitor monitor) {
SCAFormEditor.this.validator.validate();
final Viewer viewer = getViewer();
if (viewer != null) {
viewer.refresh();
}
return Status.OK_STATUS;
}
};
job.setSystem(true);
job.setUser(false);
// Validation Job should be DECORATE Priority; schedule for future to allow resource reload to complete.
job.setPriority(Job.DECORATE);
if (adapter != null) {
job.addJobChangeListener(adapter);
}
job.schedule();
}
}
/**
* @param monitor
*/
protected void internalDoValidate(final IProgressMonitor monitor) {
// result of the Validation
final BasicDiagnostic diagnostic = new BasicDiagnostic();
final List<Resource> resources = new ArrayList<Resource>();
resources.addAll(getEditingDomain().getResourceSet().getResources());
for (final Resource resource : resources) {
if (isPersisted(resource)) {
for (final EObject obj : resource.getContents()) {
this.validator.validate(obj, diagnostic);
}
}
}
if (diagnostic.getSeverity() == Diagnostic.ERROR) {
final Dialog dialog = new DiagnosticDialog(getSite().getShell(), "Invalid Model", null, diagnostic, Diagnostic.ERROR | Diagnostic.WARNING) {
@Override
protected Control createMessageArea(final Composite composite) {
this.message = "Errors have been detected. Do you want to save anyway?";
return super.createMessageArea(composite);
}
@Override
protected void createButtonsForButtonBar(final Composite parent) {
// create OK and Details buttons
createButton(parent, IDialogConstants.OK_ID, IDialogConstants.YES_LABEL, true);
createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.NO_LABEL, true);
createDetailsButton(parent);
}
};
if (dialog.open() != Window.OK) {
if (monitor != null) {
monitor.setCanceled(true);
}
throw new OperationCanceledException();
}
}
}
/**
* @return
*/
public boolean isDisposed() {
return this.disposed;
}
/**
* {@inheritDoc}
*/
@Override
public Viewer getViewer() {
final IFormPage page = this.getActivePageInstance();
if (page instanceof IViewerProvider) {
return ((IViewerProvider) page).getViewer();
}
return null;
}
@Override
public int addPage(final IFormPage page) throws PartInitException {
return super.addPage(page);
};
/**
* @since 6.0
*/
public TextEditor createTextEditor(final IEditorInput input) {
try {
return new org.eclipse.wst.sse.ui.StructuredTextEditor();
} catch (final NoClassDefFoundError e) {
return new TextEditor();
}
}
/**
* Adds a complete editor part to the multi-page editor and associates an editor document with a resource; adds a
* document listener to allow document changes to be propagated to the resource.
*
* @param editor the nested editor
* @param input the input of the nested editor
* @param resource the resource to associate with the editor
* @return the index of the page in the editor
* @throws PartInitException
* @since 4.0
*/
public int addPage(final IEditorPart editor, final IEditorInput input, final Resource resource) throws PartInitException {
return addPage(-1, editor, input, resource);
}
/**
* Adds a complete editor part to the multi-page editor and associates an editor document with a resource; adds a
* document listener to allow document changes to be propagated to the resource.
*
* @param editor the nested editor
* @param input the input of the nested editor
* @param resource the resource to associate with the editor
* @return the index of the page in the editor
* @throws PartInitException
* @since 6.0
*/
public int addPage(int index, final IEditorPart editor, final IEditorInput input, final Resource resource) throws PartInitException {
if (index == -1) {
index = super.addPage(editor, input);
} else {
super.addPage(index, editor, input);
}
if (editor instanceof TextEditor) {
final IDocument document = ((TextEditor) editor).getDocumentProvider().getDocument(editor.getEditorInput());
this.resourceToDocumentMap.put(resource, document);
document.addDocumentListener(new IDocumentListener() {
@Override
public void documentAboutToBeChanged(final DocumentEvent documentEvent) {
// Ignore
}
@Override
public void documentChanged(final DocumentEvent documentEvent) {
try {
if (SCAFormEditor.this.handledStructuredModelChange) {
SCAFormEditor.this.handledStructuredModelChange = false;
} else {
handleDocumentChange(resource);
}
} catch (final Exception exception) { // SUPPRESS CHECKSTYLE Fallback
// PASS
}
}
});
}
return index;
}
/**
* Updates a {@link Resource} with changes to its associated document.
*
* @param document the document that changed
* @since 4.0
*/
protected void handleDocumentChange(final Resource resource) {
final IDocument document = this.resourceToDocumentMap.get(resource);
final XMLResource xmlResource = (XMLResource) resource;
try {
if (xmlResource.isLoaded()) {
xmlResource.unload();
}
xmlResource.load(new InputSource(new StringReader(document.get())), xmlResource.getDefaultLoadOptions());
} catch (final Exception exception) { // SUPPRESS CHECKSTYLE Fallback
// PASS - Allow the validators to do their job rather than prevent invalid xml
}
}
/**
* Updates each document associated with this editor based on its associated {@link Resource} changes.
*
* @since 4.0
*/
protected void handleStructuredModelChange(final EventObject event) {
if (isDisposed()) {
return;
}
if (event.getSource() instanceof TransactionalCommandStack) {
final TransactionalCommandStack stack = ((TransactionalCommandStack) event.getSource());
if (stack.getMostRecentCommand() != null) {
final Collection< ? > objects = stack.getMostRecentCommand().getAffectedObjects();
if (objects.isEmpty()) {
updateAllDocs();
} else {
for (final Object obj : objects) {
final Resource resource = getResourceForObject(obj);
if (resource != null) {
updateDocument(resource);
}
}
}
} else {
updateAllDocs();
}
}
}
private Resource getResourceForObject(Object object) {
object = AdapterFactoryEditingDomain.unwrap(object);
if (object instanceof EObject) {
return ((EObject) object).eResource();
}
return null;
}
private void updateAllDocs() {
for (Resource r : resourceToDocumentMap.keySet()) {
updateDocument(r);
}
}
/**
* Updates the document that maps to the given resource.
* @param resource The EMF Resource object which has been changed. This resource must be
* within the resource to document map in order to pull up the corresponding document.
*/
private void updateDocument(final Resource resource) {
if (this.resourceToDocumentMap.containsKey(resource)) {
final IDocument document = this.resourceToDocumentMap.get(resource);
// taken from org.eclipse.xsd.presentation.XSDEditor
final ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
resource.save(out, null);
final String newContent = out.toString();
final String oldContent = document.get();
int startIndex = 0;
while (startIndex < newContent.length() && startIndex < oldContent.length() && newContent.charAt(startIndex) == oldContent.charAt(startIndex)) {
++startIndex;
}
int newEndIndex = newContent.length() - 1;
int oldEndIndex = oldContent.length() - 1;
while (newEndIndex >= startIndex && oldEndIndex >= startIndex && newContent.charAt(newEndIndex) == oldContent.charAt(oldEndIndex)) {
--newEndIndex;
--oldEndIndex;
}
final String replacement = newContent.substring(startIndex, newEndIndex + 1);
final int length = oldEndIndex - startIndex + 1;
// Only replace if there is actually a change
if (!"".equals(replacement) || length != 0) {
// Ignore this change in the document listener, since it originates with a change that is being
// made in response to some other modification
this.handledStructuredModelChange = true;
document.replace(startIndex, length, replacement);
}
} catch (final Exception exception) { // SUPPRESS CHECKSTYLE Fallback
// PASS
}
}
}
/**
* @since 7.0
*/
public List< ? > getPages() {
if (this.pages == null) {
return null;
}
return Collections.unmodifiableList((List< ? >) this.pages);
}
/**
* @since 2.0
*/
public abstract List<Object> getOutlineItems();
/**
* @return
* @since 2.1
*/
public IdlLibrary getIdlLibrary() {
return RedhawkUiActivator.getDefault().getIdlLibraryService().getLibrary();
}
/**
* @throws CoreException
* @since 6.0
*/
public void reloadIdlLibrary() {
if (reloadLibraryJob == null) {
reloadLibraryJob = new RefreshIdlLibraryJob(getIdlLibrary());
}
reloadLibraryJob.schedule();
}
/**
* @throws CoreException
* @since 3.0
*/
public IdlLibrary loadIdlLibrary(final IProgressMonitor monitor) throws CoreException {
IdlLibrary library = getIdlLibrary();
if (library != null) {
IStatus status = library.getLoadStatus();
if (status == null) {
library.load(monitor);
}
}
return library;
}
/**
* @return
* @since 2.1
*/
protected List<IPath> getDefaultIdlIncludePath() {
return Collections.emptyList();
}
/**
* Sets the selection on this editor's viewer.
*
* @param collection the objects to select in the viewer
* @since 5.0
*/
public void setSelectionToViewer(final Collection< ? > collection) {
// Make sure it's okay.
//
if (collection != null && !collection.isEmpty()) {
final Collection< ? > theSelection = collection;
final Runnable runnable = new Runnable() {
@Override
public void run() {
// Try to select the items in the current content viewer of the editor.
//
final Viewer viewer = getViewer();
if (viewer != null) {
final ISelection selection = ViewerUtil.itemsToSelection(viewer, theSelection);
if (!selection.isEmpty()) {
viewer.setSelection(selection, true);
}
}
}
};
getSite().getShell().getDisplay().asyncExec(runnable);
}
}
/**
* A tracked resource has been deleted. Sub-classes may override.
*
* @since 6.0
*/
protected void resourceDeleted(final IResource resource) {
// close the editor if the resource is deleted
closeEditor(false);
}
/**
* A tracked resource has been moved. Sub-classes may override.
*
* @since 6.0
*/
protected void resourceMoved(final IResource from, final IResource to) {
// reopen the editor on the new file
if (to instanceof IFile) {
setInput(new FileEditorInput((IFile) to));
}
}
/**
* @since 8.0
*/
public void reload() {
reloading = true;
try {
if (getEditingDomain() != null) {
for (final Resource r : getEditingDomain().getResourceSet().getResources().toArray(new Resource[0])) {
if (r.getURI().isPlatformResource()) {
try {
WorkspaceSynchronizer.getFile(r).refreshLocal(IResource.DEPTH_ONE, null);
} catch (CoreException e) {
// PASS
}
}
r.unload();
try {
r.load(getEditingDomain().getResourceSet().getLoadOptions());
} catch (final IOException e) {
// PASS
}
}
getEditingDomain().getCommandStack().flush();
}
} finally {
reloading = false;
}
}
/**
* A tracked resource has been changed. Sub-classes may override.
*
* @param resource The resource who input has changed
* @param delta The delta that describes that change that has occurred to the associated resource
* @since 6.0
*/
protected void resourceChanged(final IResource resource, final IResourceDelta delta) {
// reload the model file for the resource which has been changed
for (final Resource r : getEditingDomain().getResourceSet().getResources()) {
final IFile file = WorkspaceSynchronizer.getFile(r);
if (file != null && file.equals(resource)) {
r.unload();
try {
r.load(getEditingDomain().getResourceSet().getLoadOptions());
updateDocument(r);
} catch (final IOException e) {
// PASS
}
}
}
if (getEditingDomain() != null) {
getEditingDomain().getCommandStack().flush();
}
}
/**
* @since 6.0
*/
public ResourceTracker getResourceTracker() {
return this.resourceTracker;
}
/**
* @since 8.0
*/
public Map<Resource, IDocument> getResourceToDocumentMap() {
return resourceToDocumentMap;
}
}